package com.ourteam.system.api;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.ourteam.frame.controller.AbstractServiceController;
import com.ourteam.frame.i18n.MessageSourceHelper;
import com.ourteam.frame.web.AppDomain;
import com.ourteam.frame.web.ApplicationModel;
import com.ourteam.frame.web.MenuItem;
import com.ourteam.frame.web.OperationResult;
import com.ourteam.system.dao.SysRoleDAOQueryBean;
import com.ourteam.system.dao.SysUserDepartmentRelateDAOQueryBean;
import com.ourteam.system.domain.ApplicationDomain;
import com.ourteam.system.domain.SysUserLoginLogBean;
import com.ourteam.system.domain.SystemModule;
import com.ourteam.system.domain.SystemProperty;
import com.ourteam.system.domain.SystemRole;
import com.ourteam.system.domain.SystemUserDepartmentRelateBean;
import com.ourteam.system.service.ISysDepartmentService;
import com.ourteam.system.service.ISysRoleService;
import com.ourteam.system.service.ISysUserService;
import com.ourteam.system.service.ISystemApplicationService;
import com.ourteam.system.service.SystemApplicationServiceFactory;

import net.ui.UIConfigFactory;
import net.ui.model.action.ActionBean;
import net.ui.model.action.ActionGroupBean;


@Controller
@RequestMapping(value = "/api/SYSTEM/auth")
public class AuthenticationAPI extends AbstractServiceController {

	/**
	 * Logger for this class
	 */
	private final Log logger = LogFactory.getLog(this.getClass());

	@Autowired
	private ISystemApplicationService systemApplicationService;

	@Autowired
	private ISysUserService sysUserService;

	@Autowired
	private ISysRoleService sysRoleService;

	@Autowired
	private ISysDepartmentService sysDepartmentService;

	@RequestMapping("/login")
	@ResponseBody
	public OperationResult login(@RequestParam("account") String userId, @RequestParam("password") String password,
			@RequestParam(value = "remberMeFlag", required = false) String remberMeFlag, HttpServletRequest request,
			HttpServletResponse response, Model model) throws Exception {

		Subject subject = SecurityUtils.getSubject();

		userId = StringUtils.trim(userId);

		password = StringUtils.trim(password);

		try {
			request.getSession().setAttribute("userId", null);

			ApplicationModel applicationModel = processLogin(subject, userId, password,
					BooleanUtils.toBoolean(remberMeFlag));

			SystemProperty[] systemProperties = SystemApplicationServiceFactory.getSystemApplicationService()
					.getSystemPropertiesByCatalog("APPLICATION");

			for (int i = 0; i < systemProperties.length; i++) {
				applicationModel.getAppConfigMap().put(systemProperties[i].getPropertyCode(),
						systemProperties[i].getPropertyValue());
			}

			changeAppDomain(0);

			request.getSession().setAttribute("appModel", applicationModel);

			SysUserLoginLogBean loginLogBean = new SysUserLoginLogBean();

			loginLogBean.setLoginTime(new Date());

			loginLogBean.setUserId(applicationModel.getUserId());

			loginLogBean.setSessionId(request.getSession().getId());

			loginLogBean.setLoginIp(request.getRemoteAddr());

			sysUserService.addSysUserLoginLog(loginLogBean);

			SysUserDepartmentRelateDAOQueryBean queryBean = new SysUserDepartmentRelateDAOQueryBean();

			queryBean.createCriteria().andSysUserIdEqualTo(applicationModel.getUserId());

			SystemUserDepartmentRelateBean[] userDepartmentRelateBeans = this.sysDepartmentService
					.querySystemUserDepartments(queryBean);

			if (ArrayUtils.isNotEmpty(userDepartmentRelateBeans)) {
				request.getSession().setAttribute("loginUserDepnName",
						userDepartmentRelateBeans[0].getDepartmentName());
				request.getSession().setAttribute("loginUserDepnId", userDepartmentRelateBeans[0].getSysDepartmentId());
			}

			request.getSession().setAttribute("loginUser", loginLogBean);

			return new OperationResult(false, "", subject.getPrincipal());

		} catch (ExcessiveAttemptsException e) {
			logger.error(e);
			request.getSession().setAttribute("userId", userId);
			// throw new BaseAppException(e.getMessage());
			return new OperationResult(true, e.getMessage(), null);
		} catch (IncorrectCredentialsException e) {

			request.getSession().setAttribute("userId", userId);
			// throw new BaseAppException("loginError.incorrectCredentials");
			return new OperationResult(true, "用户名密码错误", null);
		} catch (AuthenticationException e) {
			logger.error(e);
			return new OperationResult(true, "用户名密码错误", null);

		} catch (Exception e) {
			logger.error(e);
			return new OperationResult(true, e.getMessage(), null);
		}

	}

	protected ApplicationModel processLogin(Subject subject, String account, String password, boolean rememberMe)
			throws Exception {

		UsernamePasswordToken authenticationToken = new UsernamePasswordToken();

		authenticationToken.setUsername(account);
		authenticationToken.setPassword(password.toCharArray());
		authenticationToken.setRememberMe(rememberMe);

		subject.login(authenticationToken);

		return (ApplicationModel) subject.getPrincipal();

	}

	public AppDomain changeAppDomain(long domainId) throws Exception {

		Subject subject = SecurityUtils.getSubject();

		ApplicationModel applicationModel = (ApplicationModel) subject.getPrincipal();

		long[] roleIds = AuthorityUtils.getAccountRoles(subject);

		AppDomain[] appDomains = getAppDomains(roleIds);

		applicationModel.setAppDomains(Arrays.asList(appDomains));

		if (domainId == 0 && ArrayUtils.isNotEmpty(appDomains)) {
			applicationModel.setSelectedDomainId(appDomains[0].getId());
		} else {
			applicationModel.setSelectedDomainId(domainId);
		}

		if (ArrayUtils.isNotEmpty(appDomains)) {

			for (int i = 0; i < appDomains.length; i++) {
				AppDomain appDomain = appDomains[i];

				MenuItem[] menuItems = getDomainMenuItems(appDomain.getId(), 0, roleIds);

				appDomain.setMenuItems(menuItems);
			}

		}

		for (int i = 0; i < appDomains.length; i++) {
			AppDomain appDomain = appDomains[i];
			if (appDomain.getId() == applicationModel.getSelectedDomainId()) {
				applicationModel.setSelectedDoamin(appDomain);
			}

		}

		return applicationModel.getSelectedDoamin();

	}

	protected AppDomain[] getAppDomains(long[] roleIds) throws Exception {

		if (ArrayUtils.isEmpty(roleIds)) {
			return new AppDomain[0];
		}

		List<AppDomain> applicationDomains = new ArrayList<AppDomain>();

		ApplicationDomain[] domains = this.systemApplicationService.getApplicationDomains();

		SysRoleDAOQueryBean queryBean = new SysRoleDAOQueryBean();

		queryBean.createCriteria().andIdIn(roleIds);

		List<Long> domainIds = new ArrayList<Long>();

		SystemRole[] systemRoles = this.sysRoleService.querySysRoles(queryBean);

		for (int i = 0; i < systemRoles.length; i++) {
			SystemRole systemRole = systemRoles[i];
			if (domainIds.contains(systemRole.getDomainId()) == false) {
				domainIds.add(systemRole.getDomainId());
			}
		}

		for (int i = 0; i < domains.length; i++) {

			ApplicationDomain applicationDomain = domains[i];

			if (domainIds.contains(applicationDomain.getId())) {

				AppDomain appDomain = new AppDomain();

				appDomain.setCode(applicationDomain.getCode());

				appDomain.setIcon(applicationDomain.getIcon());

				appDomain.setPage(applicationDomain.getSmallIcon());

				appDomain.setId(applicationDomain.getId());

				appDomain.setName(applicationDomain.getName());

				appDomain.setShortName(applicationDomain.getShortName());

				applicationDomains.add(appDomain);
			}

		}

		return applicationDomains.toArray(new AppDomain[applicationDomains.size()]);
	}

	protected MenuItem[] getDomainMenuItems(long appDomainId, long parentModuleId, long[] roleIds) throws Exception {

		List<MenuItem> menuItems = new ArrayList<MenuItem>();

		SystemModule[] modules = this.systemApplicationService.getSystemModules(appDomainId, parentModuleId);

		SystemModule[] canAccessModules = this.sysRoleService.getSysRoleModules(roleIds);

		if (null == modules) {
			throw new Exception(MessageSourceHelper.getText("menu.error.null"));
		}
		for (int i = 0; i < modules.length; i++) {
			SystemModule systemModule = modules[i];

			if (ArrayUtils.contains(canAccessModules, systemModule) == false) {
				continue;
			}

			MenuItem menuItem = new MenuItem();

			menuItem.setMenuId(systemModule.getId());

			menuItem.setLabel(systemModule.getModuleName());

			menuItem.setIcon(systemModule.getModuleIcon());

			menuItem.setPath(systemModule.getModuleCode());

			menuItem.setDomainId(systemModule.getDomainId());

			menuItem.setDomainCode(systemModule.getDomainCode());

			MenuItem[] subItems = getDomainMenuItems(appDomainId, systemModule.getId(), roleIds);

			menuItem.setSubItems(subItems);

			menuItems.add(menuItem);
		}

		return menuItems.toArray(new MenuItem[menuItems.size()]);
	}

	@RequestMapping("/getUserActionGroupBean")
	@ResponseBody
	public ActionGroupBean getUserActionGroupBean(@RequestParam String modelId, @RequestParam String actionGroupId,
			HttpServletRequest request, Model model) throws Exception {

		Subject subject = SecurityUtils.getSubject();

		ActionGroupBean actionGroupBean = UIConfigFactory.getInstance(actionGroupId)
				.getActionGroupConfig(actionGroupId);

		if (actionGroupBean == null) {
			throw new Exception("Can not found ActionGroup By ID : '" + actionGroupId);
		} else {

			ActionGroupBean groupBean = new ActionGroupBean();

			groupBean.setId(actionGroupBean.getId());

			ActionBean[] actionBeans = actionGroupBean.getActionBeans();

			for (int i = 0; i < actionBeans.length; i++) {
				if (AuthorityUtils.canExecuteAction(subject, modelId, actionBeans[i])) {
					groupBean.addActionBean(actionBeans[i]);
				}
			}

			return groupBean;
		}
	}

	@RequestMapping("/getLoginInfo")
	@ResponseBody
	public ApplicationModel getLoginInfo(HttpServletRequest request, Model model) throws Exception {

		Subject subject = SecurityUtils.getSubject();

		ApplicationModel applicationModel = (ApplicationModel) subject.getPrincipal();

		return applicationModel;

	}

}
